﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SharedGenomics.Domain
{
    /// <summary>
    /// Utility class for dealing with Chromosome values - chromosomes are simply modelled as ints and this class provides parsing and validation for any 
    /// chromosome values loaded from external sources. It should probably be a struct instead...
    /// </summary>
    public static class Chromosome
    {
        #region Public Methods

        public static bool IsHaploid(int chromosomeIndex)
        {
            return (chromosomeIndex == 24 || chromosomeIndex == 26);
        }

        public static bool IsSexChromosome(int chromosomeIndex)
        {
            return (chromosomeIndex == X);
        }

        public static bool IsValid(int chromosomeIndex)
        {
            //TODO: check this...
            return (chromosomeIndex > 0 && chromosomeIndex < 27);
        }

        public static int Parse(string str)
        {
            int chromosomeIndex;
            Exception ex;

            if (TryParse(str, out chromosomeIndex, out ex))
                return chromosomeIndex;
            else
                throw ex;
        }

        public static bool TryParse(string str, out int chromosomeIndex)
        {
            Exception discarded;
            return TryParse(str, out chromosomeIndex, out discarded);
        }

        #endregion

        #region Private Methods

        private static bool TryParse(string str, out int chromosomeIndex, out Exception ex)
        {
            //initialise out parameters
            chromosomeIndex = 0;
            ex = null;

            if (str == null)
            {
                ex = new ArgumentNullException("str");
                return false;
            }

            string trimmedInput = str.Trim();

            switch (trimmedInput.ToUpper())
            {
                case "X":
                    chromosomeIndex = X;
                    break;

                case "Y":
                    chromosomeIndex = Y;
                    break;

                case "XY":
                    chromosomeIndex = XY;
                    break;

                case "MT":
                    chromosomeIndex = MT;
                    break;

                default:
                {
                    int index;
                    if (Int32.TryParse(trimmedInput, out index))
                    {
                        if (IsValid(index))
                        {
                            chromosomeIndex = index;
                        }
                        else
                        {
                            ex = new ArgumentOutOfRangeException(String.Format("Index {0} is out of range for a human chromosome", index));
                            return false;
                        }
                    }
                    else
                    {
                        ex = new FormatException("The input string does not contain a valid chromosome");
                        return false;
                    }

                    break;
                }
            }

            return true;
        }


        #endregion

        #region Properties

        public static int X
        {
            get { return 23; }
        }

        public static int Y
        {
            get { return 24; }
        }

        public static int XY
        {
            get { return 25; }
        }

        public static int MT
        {
            get { return 26; }
        }

        #endregion
    }
}
